/**
 * Copyright (c) 2009 blurredVision
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 
 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __TREE_H__
#define __TREE_H__

#pragma once

#include <string>
#include <vector>

template <class T>
class DLL_EXPORT Tree
{
public:
	Tree(void);
	Tree(unsigned int idx, T* = NULL);
	// TODO implement destructor
	virtual ~Tree(void);

	void addBranch(Tree<T>* branch);
	Tree* removeBranch(Tree<T>* branch);

	void setForcedNext(Tree<T>* branch);

	const unsigned int getIdx() const;

	// TODO Tree* findBranch(const std::string &name)

	int getNumBranches() const;

	Tree* getForcedNext() const;

	Tree* getBranch(int index) const;
	Tree* getParent() const;

	T* getAttachedResource() const;
	void setAttachedResource(T* attach);

private:
	void setParent(Tree* parent);

	std::vector<Tree*>	vBranches;
	Tree*				pParent;

	Tree*               pForcedNext;

	T*					pAttached;

	unsigned int		uiIdx;
};

template <class T>
Tree<T>::Tree(void)
: pParent(NULL), pAttached(NULL), pForcedNext(NULL)
{
}

template <class T>
Tree<T>::Tree(unsigned int idx, T* attach)
: uiIdx(idx), pParent(NULL), pAttached(attach), pForcedNext(NULL)
{
}

template <class T>
Tree<T>::~Tree(void)
{
	// Delete the attached resource
	DELETE_POINTER(pAttached);

	// Delete all branches
	std::vector<Tree<T>*>::iterator it;
	for (it = vBranches.begin(); it != vBranches.end(); ++it) 
		delete (*it);
	vBranches.clear();
}

template <class T>
void Tree<T>::addBranch(Tree<T> *branch)
{
	vBranches.push_back(branch);
	branch->setParent(this);
}

template <class T>
Tree<T>* Tree<T>::removeBranch(Tree<T> *branch)
{
	Tree* retTree = NULL;
	std::vector<Tree<T>*>::iterator it;
	for (it = vBranches.begin(); it != vBranches.end(); ++it) 
		if (*it == branch) {
			retTree = *it;
			retTree->setParent(NULL);
			vBranches.erase(it);
		}
	return retTree;
}

template <class T>
int Tree<T>::getNumBranches() const
{
	return static_cast<int>( vBranches.size() );
}

template <class T>
Tree<T>* Tree<T>::getBranch(int index) const
{
	return vBranches.at(index);
}

template <class T>
Tree<T>* Tree<T>::getParent() const
{
	return pParent;
}

template <class T>
void Tree<T>::setParent(Tree* parent)
{
	pParent = parent;
}

template <class T>
T* Tree<T>::getAttachedResource() const
{
	return pAttached;
}

template <class T>
void Tree<T>::setAttachedResource(T* attach)
{
	pAttached = attach;
}

template <class T>
const unsigned int Tree<T>::getIdx() const
{
	return uiIdx;
}

template <class T>
Tree<T>* Tree<T>::getForcedNext() const
{
	return pForcedNext;
}

template <class T>
void Tree<T>::setForcedNext(Tree<T>* branch)
{
	branch->setParent(this);
	pForcedNext = branch;
}

#endif
